Install Packages

#Install and Load Packages
install.packages("corrplot")
install.packages("data.table")
library(devtools)
install_github("raivokolde/pheatmap")
install.packages("RColorBrewer")
install.packages("ggstatsplot")
install.packages("later")
install.packages("stringdist")
install.packages("sjstats")
install.packages("tidytext")
install.packages("dplyr")
install.packages("stringr")
require(devtools)
install_github("lchiffon/wordcloud2")
install.packages("tidyr")
install.packages("ggrepel")
install.packages("formattable")
install.packages("skimr")
install.packages("DT")
install.packages("devtools") # if you have not installed "devtools" package
devtools::install_github("xvrdm/ggrough")
install.packages("FFTrees")

Load Packages

library(pheatmap)
library(data.table)
library(corrplot)
library(ggplot2)
library(plyr)
library(RColorBrewer)
library(later)
library(stringdist)
library(sjstats)
library(ggstatsplot)
library(tidytext)
library(dplyr)
library(stringr)
library(rtweet)
library(wordcloud2)
library(tidyr)
library(ggrepel)
library(skimr)
library(formattable)
library(DT)
library(ggrough)
library(FFTrees)
library(knitr)

Set up the color variables

Setting up some basic color variables will keep our charts neat and consistently formatted.

# Create color palettes
bluePalette <- colorRampPalette(brewer.pal(15,"Blues"))(8)
n too large, allowed maximum for palette Blues is 9
Returning the palette you asked for with that many colors
bluePalette <-bluePalette[-c(1,2)] # remove first 2 b/c they are too light to plot
bluePalette
[1] "#BAD6EB" "#88BEDC" "#539ECC" "#2A7AB9" "#0B559F" "#08306B"
bluePalette2 <- c("#C5E2F7", "#92BAD2", "#53789E", "#395877")
##Set the blue color scale since non gender specific
pinkPalette <- c("#FDAB9F", "#FE7F9C", "#DF5286", "#F5C3C2", "#FE5BAC", "#FF69B4", "#FB9AAC")
#set the male, female color scale
genderNeutralCol <- "#C6AE74"
girlCol <- "#E07478"
boyCol <- "#588CA8"
  
mfPalette <- c(genderNeutralCol, girlCol, boyCol)

Bring in the data sets

#Bring in the data set
df= fread('https://raw.githubusercontent.com/lgellis/STEM/master/DATA-ART-1/Data/FinalData.csv')
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  6213  100  6213    0     0  66181      0 --:--:-- --:--:-- --:--:-- 66806
attach(df)
The following object is masked _by_ .GlobalEnv:

    Career

The following objects are masked from df (pos = 3):

    Career, Gender, Grade, Horoscope, HrsHomework, ID, IntExt, OptPest, PhysActive,
    ScreenTime, Self1, Self2, Sleep, SpendTime1, SpendTime2, Subject, Superpower

The following objects are masked from df (pos = 12):

    Career, Gender, Grade, Horoscope, HrsHomework, ID, IntExt, OptPest, PhysActive,
    ScreenTime, Self1, Self2, Sleep, SpendTime1, SpendTime2, Subject, Superpower

The following objects are masked from df (pos = 14):

    Career, Gender, Grade, Horoscope, HrsHomework, ID, IntExt, OptPest, PhysActive,
    ScreenTime, Self1, Self2, Sleep, SpendTime1, SpendTime2, Subject, Superpower
#Bring in the data with normalized job descr
dfNormal <- fread('https://raw.githubusercontent.com/lgellis/STEM/master/DATA-ART-1/Data/FinalDataNormalizedCareer.csv')
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  6087  100  6087    0     0  57725      0 --:--:-- --:--:-- --:--:-- 57971
head(dfNormal)

Data visualization

Correlation charts

See how the variables collected relate to one another

#######################   CORRELATION ##############################
# Create the Correlation Plots
corDf <- df[ , 8:11]
corDf <-sapply(corDf, FUN = as.numeric) 
corDf <-corDf[complete.cases(corDf), ]
#Make the correlation matrix
corMatrix <-cor(corDf, use="complete.obs", method="pearson")
corMatrix
            ScreenTime       Sleep  PhysActive HrsHomework
ScreenTime   1.0000000 -0.48038694 -0.17562140   0.2181979
Sleep       -0.4803869  1.00000000  0.01483157  -0.0534581
PhysActive  -0.1756214  0.01483157  1.00000000   0.1147035
HrsHomework  0.2181979 -0.05345810  0.11470353   1.0000000
#Plot numerous formats of the correlation matrix
corrplot(corMatrix, type = "upper", order = "hclust", col = c("black", "white"), bg = "lightblue", tl.col = "black")

corrplot(corMatrix, method="circle", tl.col = "black")

corrplot(corMatrix, method="square", tl.col = "black")

corrplot(corMatrix, method="number", tl.col = "black")

corrplot(corMatrix, method="shade", tl.col = "black")

corrplot.mixed(corMatrix, tl.col = "black")

Scatterplots and Gender

#Gender Based Graphs
# please ignore all of the lazy naming :) 
#Screen, Sleep and Gender
scat2 <-ggplot(df, aes(x=Sleep, y=ScreenTime, colour=Gender))
scat2 <- scat2 + scale_color_manual(values= mfPalette) + geom_count() 
scat2 +  theme_bw() + theme_minimal() +  
  facet_wrap( ~ Gender, ncol=2) +
  labs(title = "Time Spent on Screen vs Sleep Considering Gender",
       x = "Hours of Sleep per Night", y = "Hours of Screen Time Per Day")

#Screen, Sleep, Physical Activity and Gender
scat2 <-ggplot(df, aes(x=Sleep, y=ScreenTime, colour=Gender, size=PhysActive))
scat2 <- scat2 + scale_color_manual(values= mfPalette) + geom_point() 
scat2 +  theme_bw() + theme_minimal() +
  facet_wrap( ~ Gender, ncol=2) +
  labs(title = "Time Spent on Screen vs Sleep Considering Gender and Physical Activity",
       x = "Hours of Sleep per Night", y = "Hours of Screen Time Per Day")

#Homework, Sleep, Physical Activity and Gender
scat2 <-ggplot(df, aes(x=Sleep, y=HrsHomework, colour=Gender, size=PhysActive))
scat2 <- scat2 + scale_color_manual(values= mfPalette) + geom_point() 
scat2 +  theme_bw() + theme_minimal() +
  facet_wrap( ~ Gender, ncol=2) +
  labs(title = "Time Spent on Homwork vs Sleep Considering Gender and Physical Activity",
       x = "Hours of Sleep per Night", y = "Hours of Homework Time Per Week")

Scatterplots exploring sleep time and screen time

# Numerical Relations
#Sleep and Screentime 
scat2 <-ggplot(df, aes(x=Sleep, y=ScreenTime, size=1/5, alpha=0.05))
scat2 <- scat2  + geom_point() 
scat2 +  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=2) +
  theme_bw() + theme_minimal() +
  labs(title = "Time Spent on Sleep vs Screen Time",
       x = "Hours of Sleep per Night", y = "Hours of Screen Time Per Day") 

#Sleep and Grade 
scat2 <-ggplot(df, aes(x=Sleep, y=Grade, size=1/5, alpha=0.05))
scat2 <- scat2  + geom_point() 
scat2 +  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=2) +
  theme_bw() + theme_minimal() +
  labs(title = "Time Spent on Sleep vs Grade",
       x = "Hours of Sleep per Night", y = "Grade") 

#ScreenTime and Grade 
scat2 <-ggplot(df, aes(x=ScreenTime, y=Grade, size=1/5, alpha=0.05))
scat2 <- scat2  + geom_point() 
scat2 +  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=2) +
  theme_bw() + theme_minimal() +
  labs(title = "Screen Time vs Grade",
       x = "Hours of Screen Time", y = "Grade") 

#Sleep and Screentime - Facet Wrap by Grade to see if it's a common trend without age 
# as confounding factor
scat2 <-ggplot(df, aes(x=Sleep, y=ScreenTime, alpha=0.05))
scat2 <- scat2 + geom_point()
scat2 +  theme_bw() + theme_minimal() +
  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=1) +
  labs(title = "Time Spent on Screen vs Sleep by Grade",
       x = "Hours of Sleep per Night", y = "Hours of Screen Time Per Day") +
  facet_wrap( ~ Grade, ncol=2)

More Numerical Relations

#Chart 6
violin <-ggplot(df, aes(y=Sleep, x=IntExt)) 
violin + geom_violin(trim=FALSE, fill="lightblue")  +  
  theme_bw() + theme_minimal() +
  labs(title = "Time Spent on Sleep by Social Factors",
       x = "Hours of Sleep per Night")

#Sleep, Homework and Subject
scat3 <-ggplot(df, aes(x=HrsHomework, y=Sleep, colour=Subject))
scat3<- scat3 + geom_point() + geom_smooth()
scat3 + facet_wrap( ~ Subject, ncol=2) + 
  scale_color_manual(values= bluePalette)  +
  theme_bw() + theme_minimal() +
  labs(title = "Time Spent on Homwork vs Sleep Considering Students Favorite Subject",
       x = "Hours of Sleep per Night", y = "Hours of Homework Per Week")

# Age differences
# Sleep by Age
sleepTime <-ggplot(df, aes(y=Sleep, x=Grade)) 
sleepTime + geom_count(trim=FALSE, fill="lightblue")  +  
  theme_bw() + theme_minimal() +
  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=2) +
  labs(title = "Time Spent on Sleep by Grade",
       y = "Hours of Sleep per Night", x="Grade")
Ignoring unknown parameters: trim

# Homework by Age
homeworkTime <-ggplot(df, aes(y=HrsHomework, x=Grade)) 
homeworkTime + geom_count(trim=FALSE, fill="lightblue")  +  
  theme_bw() + theme_minimal() +
  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=2) +
  labs(title = "Time Spent on Homework by Grade",
       y = "Hours of Homework per Week", x="Grade")
Ignoring unknown parameters: trim

# Physical Activity by Age
physTime <-ggplot(df, aes(y=PhysActive, x=Grade)) 
physTime + geom_count(trim=FALSE, fill="lightblue")  +  
  theme_bw() + theme_minimal() +
  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=2) +
  labs(title = "Time Spent on Physical Activity by Grade",
       y = "Hours of Physical Activity per Week", x="Grade")
Ignoring unknown parameters: trim

# Screen Time by Age
screenTime <-ggplot(df, aes(y=ScreenTime, x=Grade)) 
screenTime + geom_count(trim=FALSE, fill="lightblue")  +  
  theme_bw() + theme_minimal() +
  stat_smooth(method=lm, fill="#BAD6EB", colour="#08306B", size=2) +
  labs(title = "Time Spent on Screens by Grade",
       y = "Hours of Screen Time per Day", x="Grade")
Ignoring unknown parameters: trim

#Summary of grade - average screentime, sleep, physical activity etc
gradeSummary <- df %>%
  group_by(Grade) %>%
  summarize(ScreenTimeDay = mean(ScreenTime, na.rm = TRUE), SleepDay = mean(Sleep, na.rm = TRUE), 
            PhysActiveDay = mean(PhysActive, na.rm = TRUE), HomeworkDay = mean(HrsHomework, na.rm = TRUE))  %>%
  gather(measurement, average, ScreenTimeDay:HomeworkDay)

Combination of plots using ggstatsplot

# ggstatsplot
ggstatsplot::ggscatterstats(
  data = df, 
  x = ScreenTime, 
  y = Sleep,
  title = "Hours Sleep vs Screen Time",
  messages = FALSE, 
  marginal.type = "histogram", 
  line.color = "#08306B", 
  xfill = "#BAD6EB",                              
  yfill = "#539ECC",  
)
# plot
ggstatsplot::ggbetweenstats(
  data = df, 
  x = Gender, 
  y = HrsHomework,
  messages = FALSE
)
Warning:  aesthetic `x` was not a factor; converting it to factor

#Histogram
ggstatsplot::gghistostats(
  data = df,
  x = PhysActive,
  title = "Distribution of Physically Active Hours",
  type = "parametric",                           # one sample t-test
  test.value = 3,                                # default value is 0
  centrality.para = "mean",                      # which measure of central tendency is to be plotted
  centrality.color = "darkred",                  # decides color of vertical line representing central tendency
  binwidth = 0.10,                               # binwidth value (experiment until you find the best one)
  messages = FALSE                               # turn off the messages
) 

Word Clouds

Career

careerGirl %>%
  mutate(word = reorder(word, n)) %>%
  arrange(desc(n)) %>%
  slice(1:10) %>%
  ggplot(aes(word, n)) +
  geom_col(show.legend = FALSE, fill=girlCol) +
  labs(title = "Top 10 Girl Careers",
       y=NULL, 
       x = NULL) +
  coord_flip()  +
  theme_bw() + theme_minimal()  + 
  theme(
    text = element_text(size=20, face="bold"), 
    plot.title = element_text(size=30, face="bold", hjust = 0.5))

)
Error: unexpected ')' in ")"
boyCol <- "#588CA8"
careerBoy %>%
  mutate(word = reorder(word, n)) %>%
  arrange(desc(n)) %>%
  slice(1:10) %>%
  ggplot(aes(word, n)) +
  geom_col(show.legend = FALSE, fill=boyCol) +
  labs(title = "Top 10 Boy Careers",
       y=NULL, 
       x = NULL) +
  coord_flip()  +
  theme_bw() + theme_minimal()  + 
  theme(
    text = element_text(size=20, face="bold"), 
    plot.title = element_text(size=30, face="bold", hjust = 0.5))

Hobbies word clouds

Self perception

#Combine the hobbies column
dfNormal$self <- paste(dfNormal$Self1, dfNormal$Self2, sep= " ")
dfNormal$self
  [1] "active competitive"            "kind active"                   "active creative"              
  [4] "active responsible"            "intellegent strong"            "funny active"                 
  [7] "joyful lazy"                   "fun confident"                 "sad calm"                     
 [10] "smart tired"                   "funny athletic"                "caring responsible"           
 [13] "kind active"                   "living annoying"               "athletic energetic"           
 [16] "idk idk"                       "idk idk"                       "awesome amazing"              
 [19] "funny  smart"                  "smart happy"                   "quite pretty"                 
 [22] "sporty smart"                  "nice kind"                     "nice happy"                   
 [25] "fun kind"                      "wierd awkward"                 "rebel small"                  
 [28] "funny loud"                    "anoying fun"                   "talk awsome"                  
 [31] "childish annoying"             "moody intense"                 "loud unpredictable"           
 [34] "shy curious"                   "creative curious"              "quiet expressive"             
 [37] "curious friendly"              "shy persistent"                "tall asian"                   
 [40] "funny energitic"               "simple n/a"                    "Sporty Strong"                
 [43] "talkative beyond not annoying" "n/a n/a"                       "creative caring"              
 [46] "talkative caring"              "empathetic kind"               "optimistic extravert"         
 [49] "nice outgoing"                 "athletic fidgety"              "Fun Sweet"                    
 [52] "pretty sporty"                 "happy kind"                    "greatful awesome"             
 [55] "cool awesome"                  "cool active"                   "generouse kind"               
 [58] "nice nice"                     "funny kind"                    "nice funny"                   
 [61] "Childish Lazy"                 "Sarcastic Sassy"               "Energetic Curious"            
 [64] "Quiet Boring"                  "Weird Active"                  "Funny Shy"                    
 [67] "Chill Tall"                    "Active Cool"                   "Intelligent Athletic"         
 [70] "Annoying Awesome"              "Athletic Amazing"              "Shy Embarassed"               
 [73] "Active Athletic"               "thoughtful friendly"           "weird odd"                    
 [76] "funny awesome"                 "active fun"                    "funny small"                  
 [79] "negative sneaky"               "friendly creative"             "funny nice"                   
 [82] "angry awesome"                 "art cats"                      "Active Smart"                 
 [85] "Kind Happy"                    "Happy Active"                  "Competetive Kind"             
 [88] "Gamer Sporty"                  "Smart Sweet"                   "Active Smart"                 
 [91] "Gamer Smart"                   "Active Smart"                  "Gamer Annoying"               
 [94] "sassy funny"                   " "                             "loyal artistic"               
 [97] "athletic social"               "funny rude"                    "funny athletic"               
[100] "jerk dishonest"                "funny  athletic"               "agressive calm"               
[103] "small funny"                   "Human Person"                  "Annoying  stuburn"            
[106] "funny confused"                "funny outgoing"                "Hilarious awesome"            
[109] "Fashionable awesome"           "smart active"                  "smart active"                 
[112] "athletic smart"                "athletic smart"                "sassy happy"                  
[115] "fun happy"                     "athletic thiccc"               "funny annoying"               
[118] "smart blonde"                  "the goat"                      "smart nice"                   
[121] "calm happy"                    "overly energetic impatient"    "funny athletic"               
[124] "Bookworm Annoying"             "Wierd Crazy"                   "Chill Dude"                   
[127] "Witty Condesending"            "Smart Sporty"                  "Lazy Gifted"                  
[130] "Smart Video Game Lover"        "Smart Extreverted"             "Friendly Shy"                 
[133] "Fun Extreverted"               "athletic intelligent"          "weird cool"                   
[136] "cheerful optimistic"           "petty basic"                   "adventurous n/a"              
[139] "peculiar sassy"                "cool cat"                      "small blond"                  
[142] "funny athletic"                "laid back setericle"           "shy active"                   
[145] "active sporty"                 "different hungry"              " weird"                       
[148] "hungry friendly"               "smart smart"                   "positive lazy"                
[151] "lazy pretty"                   "unsure smart"                  "shy fun"                      
[154] "empathetic observant"          "clueless funny"                "determined caring"            
[157] "talkative witty"               "happy annoying"                "funny loyal"                  
[160] "fun caring"                    "extraverted sassy"             "free spirited creative"       
[163] "happy good"                    "weird korean"                  "happy shy"                    
[166] "lazy  energetic"               "active  tall"                  "short active"                 
[169] "shy quiet"                     "emotional  kind"               "active  tall"                 
[172] "active  happy"                 "calm funny"                    "friendly funny"               
[175] "indecisive active"             "fun cool"                      "lazy funky"                   
[178] "sporty smart"                  "load energitic"                "fun energetic"                
[181] "agressive anoying"             "nice smart"                    "fun energetic"                
[184] "hyper flimsy"                  "tired smart"                  
#Unnest the words - code via Tidy Text
table2 <- dfNormal %>% 
  unnest_tokens(word, self)
#remove stop words - aka typically very common words such as "the", "of" etc
self <- table2 %>%
  anti_join(stop_words) 
Joining, by = "word"
self
selfGirl <- table2 %>%
  anti_join(stop_words) %>%
  filter(Gender == "female")
Joining, by = "word"
selfBoy <- table2 %>%
  anti_join(stop_words) %>%
  filter(Gender == "male")
Joining, by = "word"
#do a word count
self <- self %>%
  dplyr::count(word, sort = TRUE) 
self 
selfGirl <- selfGirl %>%
  dplyr::count(word, sort = TRUE) 
selfGirl
selfBoy <- selfBoy %>%
  dplyr::count(word, sort = TRUE) 
selfBoy
#download symbol
url <- "https://github.com/lgellis/STEM/blob/master/DATA-ART-1/Symbols/heart.png?raw=true"
heartimg <- "heart.png"
download.file(url, heartimg) # download file
trying URL 'https://github.com/lgellis/STEM/blob/master/DATA-ART-1/Symbols/heart.png?raw=true'
Content type 'image/png' length 28086 bytes (27 KB)
==================================================
downloaded 27 KB
#Make wordcloud
wordcloud2(self, size=1)

wordcloud2(self, size=3, figPath = heartimg )

wordcloud2(selfBoy, size=1.5, figPath = heartimg, color=boyCol )

wordcloud2(selfGirl, size=1.5, figPath = heartimg, color=girlCol )

# Self bar charts
selfGirl$gender <- 'female'
selfBoy$gender <- 'male'
fullSelf <-rbind(selfBoy, selfGirl)
fullSelf
fullSelf %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n, fill = gender)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~gender, scales = "free_y") +
  scale_fill_manual(values=c(girlCol, boyCol)) +
  labs(y = "Male vs Female Self Description",
       x = NULL) +
  coord_flip()  +
  theme_bw() + theme_minimal() 

Self perception sentiment analysis

# Sentiment Analysis - do on the full data
?get_sentiments
#afinn is numeric scale, bing is +ve/-ve, 
#nrc is more detailed (ie trust, fear etc), loughran is +ve/-ve
sentiments <- get_sentiments("afinn") 
sentiments
## Get raw word and gender (1 row per instance of assignment)
head(dfNormal)
self1 <- as.data.frame(dfNormal[,c("Gender", "Self1")])
self2 <- as.data.frame(dfNormal[,c("Gender", "Self2")])
head(self2)
#TO DO rename self1 and self2 
names(self1)[2]<-"word"
names(self2)[2]<-"word"
fullStackSelf <-rbind(self1, self2)
head(fullStackSelf)
#add sentiment
sentiments <- get_sentiments("afinn") 
fullStackSelfSentiment <- fullStackSelf %>%
  inner_join(sentiments)
Joining, by = "word"
fullStackSelfSentiment
#Averages
summaryGenderSentiment <- fullStackSelfSentiment %>% 
  group_by(Gender) %>%
  dplyr::summarize(avgSentimentScore = mean(score, na.rm = TRUE), 
            medSentimentScore = median(score, na.rm = TRUE), 
            countWords = length(word))
names(summaryGenderSentiment) <- c("Gender", "Avg Sentiment Score", "Median Sentiment Score", "Word Count")
formattable(summaryGenderSentiment, 
            list("Avg Sentiment Score" = color_tile("transparent", "#00A86B")))

as.datatable(formattable(summaryGenderSentiment))

#box plot
ggplot(fullStackSelfSentiment, aes(x=Gender, y=score, fill=Gender)) + 
  geom_boxplot(notch=TRUE) +
  scale_fill_manual(values=c(genderNeutralCol, girlCol, boyCol)) +
  labs(title = "Sentiment Score for Male vs Female Self Description",
       x = NULL) +
  coord_flip()  +
  theme_bw() + theme_minimal() + 
  theme(
    text = element_text(size=14 ), 
    plot.title = element_text(size=18, face="bold", hjust = 0.5))

Animations

Note that the output will not be displayed in

##normal
screenTime <-ggplot(df, aes(y=ScreenTime, x=PhysActive)) 
screenTime + geom_count(trim=FALSE, fill="lightblue")  +  
  theme_bw() + theme_minimal() + 
  labs(title = "Time Spent on Screens by Grade",
       y = "Hours of Screen Time per Day", x="Hours Physically Active a Week")
Ignoring unknown parameters: trim
#The docs can be found here: https://github.com/thomasp85/gganimate/blob/master/README.md
library(gganimate)
library(tweenr)
library(gganimate)
##With Animation
screenTime <-ggplot(df, aes(y=ScreenTime, x=HrsHomework)) 
screenTime + geom_count(trim=FALSE, fill="lightblue")  +  
  theme_bw() + theme_minimal() + 
  # Here comes the gganimate specific bits
  labs(title = 'Grade: {frame_time}', x = 'Hours Homework a Week', y = 'Hours of Screen Time per Day') +
  transition_time(Grade) +
  ease_aes('linear')
Ignoring unknown parameters: trim

Frame 0 (1%)
Frame 1 (2%)
Frame 2 (3%)
Frame 3 (4%)
Frame 4 (5%)
Frame 5 (6%)
Frame 6 (7%)
Frame 7 (8%)
Frame 8 (9%)
Frame 9 (10%)
Frame 10 (11%)
Frame 11 (12%)
Frame 12 (13%)
Frame 13 (14%)
Frame 14 (15%)
Frame 15 (16%)
Frame 16 (17%)
Frame 17 (18%)
Frame 18 (19%)
Frame 19 (20%)
Frame 20 (21%)
Frame 21 (22%)
Frame 22 (23%)
Frame 23 (24%)
Frame 24 (25%)
Frame 25 (26%)
Frame 26 (27%)
Frame 27 (28%)
Frame 28 (29%)
Frame 29 (30%)
Frame 30 (31%)
Frame 31 (32%)
Frame 32 (33%)
Frame 33 (34%)
Frame 34 (35%)
Frame 35 (36%)
Frame 36 (37%)
Frame 37 (38%)
Frame 38 (39%)
Frame 39 (40%)
Frame 40 (41%)
Frame 41 (42%)
Frame 42 (43%)
Frame 43 (44%)
Frame 44 (45%)
Frame 45 (46%)
Frame 46 (47%)
Frame 47 (48%)
Frame 48 (49%)
Frame 49 (50%)
Frame 50 (51%)
Frame 51 (52%)
Frame 52 (53%)
Frame 53 (54%)
Frame 54 (55%)
Frame 55 (56%)
Frame 56 (57%)
Frame 57 (58%)
Frame 58 (59%)
Frame 59 (60%)
Frame 60 (61%)
Frame 61 (62%)
Frame 62 (63%)
Frame 63 (64%)
Frame 64 (65%)
Frame 65 (66%)
Frame 66 (67%)
Frame 67 (68%)
Frame 68 (69%)
Frame 69 (70%)
Frame 70 (71%)
Frame 71 (72%)
Frame 72 (73%)
Frame 73 (74%)
Frame 74 (75%)
Frame 75 (76%)
Frame 76 (77%)
Frame 77 (78%)
Frame 78 (79%)
Frame 79 (80%)
Frame 80 (81%)
Frame 81 (82%)
Frame 82 (83%)
Frame 83 (84%)
Frame 84 (85%)
Frame 85 (86%)
Frame 86 (87%)
Frame 87 (88%)
Frame 88 (89%)
Frame 89 (90%)
Frame 90 (91%)
Frame 91 (92%)
Frame 92 (93%)
Frame 93 (94%)
Frame 94 (95%)
Frame 95 (96%)
Frame 96 (97%)
Frame 97 (98%)
Frame 98 (99%)
Frame 99 (100%)
Finalizing encoding... done!

## Second Animation
ggplot(df, aes(y=ScreenTime, x=HrsHomework, color = Gender)) +
  geom_point()  +  
  theme_bw() + theme_minimal() + 
  # Here comes the gganimate specific bits
  labs(title = 'Grade: {frame_time}', x = 'Hours Homework a Week', y = 'Hours of Screen Time per Day') +
  transition_time(Grade) +
  ease_aes('linear') + 
  scale_color_manual(values=mfPalette)

Frame 0 (1%)
Frame 1 (2%)
Frame 2 (3%)
Frame 3 (4%)
Frame 4 (5%)
Frame 5 (6%)
Frame 6 (7%)
Frame 7 (8%)
Frame 8 (9%)
Frame 9 (10%)
Frame 10 (11%)
Frame 11 (12%)
Frame 12 (13%)
Frame 13 (14%)
Frame 14 (15%)
Frame 15 (16%)
Frame 16 (17%)
Frame 17 (18%)
Frame 18 (19%)
Frame 19 (20%)
Frame 20 (21%)
Frame 21 (22%)
Frame 22 (23%)
Frame 23 (24%)
Frame 24 (25%)
Frame 25 (26%)
Frame 26 (27%)
Frame 27 (28%)
Frame 28 (29%)
Frame 29 (30%)
Frame 30 (31%)
Frame 31 (32%)
Frame 32 (33%)
Frame 33 (34%)
Frame 34 (35%)
Frame 35 (36%)
Frame 36 (37%)
Frame 37 (38%)
Frame 38 (39%)
Frame 39 (40%)
Frame 40 (41%)
Frame 41 (42%)
Frame 42 (43%)
Frame 43 (44%)
Frame 44 (45%)
Frame 45 (46%)
Frame 46 (47%)
Frame 47 (48%)
Frame 48 (49%)
Frame 49 (50%)
Frame 50 (51%)
Frame 51 (52%)
Frame 52 (53%)
Frame 53 (54%)
Frame 54 (55%)
Frame 55 (56%)
Frame 56 (57%)
Frame 57 (58%)
Frame 58 (59%)
Frame 59 (60%)
Frame 60 (61%)
Frame 61 (62%)
Frame 62 (63%)
Frame 63 (64%)
Frame 64 (65%)
Frame 65 (66%)
Frame 66 (67%)
Frame 67 (68%)
Frame 68 (69%)
Frame 69 (70%)
Frame 70 (71%)
Frame 71 (72%)
Frame 72 (73%)
Frame 73 (74%)
Frame 74 (75%)
Frame 75 (76%)
Frame 76 (77%)
Frame 77 (78%)
Frame 78 (79%)
Frame 79 (80%)
Frame 80 (81%)
Frame 81 (82%)
Frame 82 (83%)
Frame 83 (84%)
Frame 84 (85%)
Frame 85 (86%)
Frame 86 (87%)
Frame 87 (88%)
Frame 88 (89%)
Frame 89 (90%)
Frame 90 (91%)
Frame 91 (92%)
Frame 92 (93%)
Frame 93 (94%)
Frame 94 (95%)
Frame 95 (96%)
Frame 96 (97%)
Frame 97 (98%)
Frame 98 (99%)
Frame 99 (100%)
Finalizing encoding... done!
ggplot(df, aes(y=ScreenTime, x=HrsHomework, color = Gender)) +
  geom_point()  +  
  theme_bw() + theme_minimal() + 
  # Here comes the gganimate specific bits
  labs(title = 'Grade: {frame_time}', x = 'Hours Homework a Week', y = 'Hours of Screen Time per Day') +
  transition_time(Grade) +
  ease_aes('sine-in-out') + 
  scale_color_manual(values=mfPalette)
## With better titles
ggplot(df, aes(y=ScreenTime, x=HrsHomework, color = Gender)) +
  geom_point(size =7, alpha = 0.4)  +  
  theme_bw() + theme_minimal() + 
  # Here comes the gganimate specific bits
  transition_states(
    Grade,
    transition_length = 4,
    state_length = 1
  ) +
  enter_fade() + 
  exit_shrink() +
  ease_aes('sine-in-out') + 
  scale_color_manual(values=mfPalette) +
  labs(title = 'Grade: {closest_state}')

Frame 0 (1%)
Frame 1 (2%)
Frame 2 (3%)
Frame 3 (4%)
Frame 4 (5%)
Frame 5 (6%)
Frame 6 (7%)
Frame 7 (8%)
Frame 8 (9%)
Frame 9 (10%)
Frame 10 (11%)
Frame 11 (12%)
Frame 12 (13%)
Frame 13 (14%)
Frame 14 (15%)
Frame 15 (16%)
Frame 16 (17%)
Frame 17 (18%)
Frame 18 (19%)
Frame 19 (20%)
Frame 20 (21%)
Frame 21 (22%)
Frame 22 (23%)
Frame 23 (24%)
Frame 24 (25%)
Frame 25 (26%)
Frame 26 (27%)
Frame 27 (28%)
Frame 28 (29%)
Frame 29 (30%)
Frame 30 (31%)
Frame 31 (32%)
Frame 32 (33%)
Frame 33 (34%)
Frame 34 (35%)
Frame 35 (36%)
Frame 36 (37%)
Frame 37 (38%)
Frame 38 (39%)
Frame 39 (40%)
Frame 40 (41%)
Frame 41 (42%)
Frame 42 (43%)
Frame 43 (44%)
Frame 44 (45%)
Frame 45 (46%)
Frame 46 (47%)
Frame 47 (48%)
Frame 48 (49%)
Frame 49 (50%)
Frame 50 (51%)
Frame 51 (52%)
Frame 52 (53%)
Frame 53 (54%)
Frame 54 (55%)
Frame 55 (56%)
Frame 56 (57%)
Frame 57 (58%)
Frame 58 (59%)
Frame 59 (60%)
Frame 60 (61%)
Frame 61 (62%)
Frame 62 (63%)
Frame 63 (64%)
Frame 64 (65%)
Frame 65 (66%)
Frame 66 (67%)
Frame 67 (68%)
Frame 68 (69%)
Frame 69 (70%)
Frame 70 (71%)
Frame 71 (72%)
Frame 72 (73%)
Frame 73 (74%)
Frame 74 (75%)
Frame 75 (76%)
Frame 76 (77%)
Frame 77 (78%)
Frame 78 (79%)
Frame 79 (80%)
Frame 80 (81%)
Frame 81 (82%)
Frame 82 (83%)
Frame 83 (84%)
Frame 84 (85%)
Frame 85 (86%)
Frame 86 (87%)
Frame 87 (88%)
Frame 88 (89%)
Frame 89 (90%)
Frame 90 (91%)
Frame 91 (92%)
Frame 92 (93%)
Frame 93 (94%)
Frame 94 (95%)
Frame 95 (96%)
Frame 96 (97%)
Frame 97 (98%)
Frame 98 (99%)
Frame 99 (100%)
Finalizing encoding... done!

Sliding histogram

Test out the graph

ggplot(df, aes(x="", y=ScreenTime)) +
  geom_boxplot(fill = genderNeutralCol, alpha = 0.8, binwidth=3)  +  
  theme_bw() + theme_minimal() + facet_wrap(~Grade)
Ignoring unknown parameters: binwidth

Make the animation

ggplot(df, aes(x="", y=ScreenTime)) +
  geom_boxplot(fill = boyCol, alpha = 0.8, binwidth=3)  +  
  theme_bw() + theme_minimal() +
  # Here comes the gganimate specific bits
  transition_states(
    Grade,
    transition_length = 4,
    state_length = 1
  ) +
  enter_fade() + 
  exit_shrink() +
  ease_aes('sine-in-out') + 
  scale_color_manual(values=mfPalette) +
  labs(title = 'Grade: {closest_state}', 
        x ="", y = "Screen Time") +
  theme(
    plot.title = element_text(size=30, face="bold.italic", hjust = 0.5),
    axis.title.y = element_text(size=14, face="bold")
)
Ignoring unknown parameters: binwidth
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQotLS0KdGl0bGU6ICJSIE5vdGVib29rIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDpkZWZhdWx0CiAgd29yZF9kb2N1bWVudDogZGVmYXVsdAotLS0KCiMgSW5zdGFsbCBQYWNrYWdlcwoKYGBge3J9CiNJbnN0YWxsIGFuZCBMb2FkIFBhY2thZ2VzCmluc3RhbGwucGFja2FnZXMoImNvcnJwbG90IikKaW5zdGFsbC5wYWNrYWdlcygiZGF0YS50YWJsZSIpCmxpYnJhcnkoZGV2dG9vbHMpCmluc3RhbGxfZ2l0aHViKCJyYWl2b2tvbGRlL3BoZWF0bWFwIikKaW5zdGFsbC5wYWNrYWdlcygiUkNvbG9yQnJld2VyIikKaW5zdGFsbC5wYWNrYWdlcygiZ2dzdGF0c3Bsb3QiKQppbnN0YWxsLnBhY2thZ2VzKCJsYXRlciIpCmluc3RhbGwucGFja2FnZXMoInN0cmluZ2Rpc3QiKQppbnN0YWxsLnBhY2thZ2VzKCJzanN0YXRzIikKaW5zdGFsbC5wYWNrYWdlcygidGlkeXRleHQiKQppbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpCmluc3RhbGwucGFja2FnZXMoInN0cmluZ3IiKQpyZXF1aXJlKGRldnRvb2xzKQppbnN0YWxsX2dpdGh1YigibGNoaWZmb24vd29yZGNsb3VkMiIpCmluc3RhbGwucGFja2FnZXMoInRpZHlyIikKaW5zdGFsbC5wYWNrYWdlcygiZ2dyZXBlbCIpCmluc3RhbGwucGFja2FnZXMoImZvcm1hdHRhYmxlIikKaW5zdGFsbC5wYWNrYWdlcygic2tpbXIiKQppbnN0YWxsLnBhY2thZ2VzKCJEVCIpCmluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikgIyBpZiB5b3UgaGF2ZSBub3QgaW5zdGFsbGVkICJkZXZ0b29scyIgcGFja2FnZQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInh2cmRtL2dncm91Z2giKQppbnN0YWxsLnBhY2thZ2VzKCJGRlRyZWVzIikKYGBgCgojTG9hZCBQYWNrYWdlcwoKYGBge3J9CmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGxhdGVyKQpsaWJyYXJ5KHN0cmluZ2Rpc3QpCmxpYnJhcnkoc2pzdGF0cykKbGlicmFyeShnZ3N0YXRzcGxvdCkKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeShkcGx5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHJ0d2VldCkKbGlicmFyeSh3b3JkY2xvdWQyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2tpbXIpCmxpYnJhcnkoZm9ybWF0dGFibGUpCmxpYnJhcnkoRFQpCmxpYnJhcnkoZ2dyb3VnaCkKbGlicmFyeShGRlRyZWVzKQpsaWJyYXJ5KGtuaXRyKQpgYGAKCgoKCiMgU2V0IHVwIHRoZSBjb2xvciB2YXJpYWJsZXMKClNldHRpbmcgdXAgc29tZSBiYXNpYyBjb2xvciB2YXJpYWJsZXMgd2lsbCBrZWVwIG91ciBjaGFydHMgbmVhdCBhbmQgY29uc2lzdGVudGx5IGZvcm1hdHRlZC4KCmBgYHtyfQoKIyBDcmVhdGUgY29sb3IgcGFsZXR0ZXMKYmx1ZVBhbGV0dGUgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDE1LCJCbHVlcyIpKSg4KQpibHVlUGFsZXR0ZSA8LWJsdWVQYWxldHRlWy1jKDEsMildICMgcmVtb3ZlIGZpcnN0IDIgYi9jIHRoZXkgYXJlIHRvbyBsaWdodCB0byBwbG90CmJsdWVQYWxldHRlCgpibHVlUGFsZXR0ZTIgPC0gYygiI0M1RTJGNyIsICIjOTJCQUQyIiwgIiM1Mzc4OUUiLCAiIzM5NTg3NyIpCgojI1NldCB0aGUgYmx1ZSBjb2xvciBzY2FsZSBzaW5jZSBub24gZ2VuZGVyIHNwZWNpZmljCnBpbmtQYWxldHRlIDwtIGMoIiNGREFCOUYiLCAiI0ZFN0Y5QyIsICIjREY1Mjg2IiwgIiNGNUMzQzIiLCAiI0ZFNUJBQyIsICIjRkY2OUI0IiwgIiNGQjlBQUMiKQoKI3NldCB0aGUgbWFsZSwgZmVtYWxlIGNvbG9yIHNjYWxlCmdlbmRlck5ldXRyYWxDb2wgPC0gIiNDNkFFNzQiCmdpcmxDb2wgPC0gIiNFMDc0NzgiCmJveUNvbCA8LSAiIzU4OENBOCIKICAKbWZQYWxldHRlIDwtIGMoZ2VuZGVyTmV1dHJhbENvbCwgZ2lybENvbCwgYm95Q29sKQoKYGBgCgojIEJyaW5nIGluIHRoZSBkYXRhIHNldHMKCmBgYHtyfQojQnJpbmcgaW4gdGhlIGRhdGEgc2V0CmRmPSBmcmVhZCgnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2xnZWxsaXMvU1RFTS9tYXN0ZXIvREFUQS1BUlQtMS9EYXRhL0ZpbmFsRGF0YS5jc3YnKQphdHRhY2goZGYpCgojQnJpbmcgaW4gdGhlIGRhdGEgd2l0aCBub3JtYWxpemVkIGpvYiBkZXNjcgpkZk5vcm1hbCA8LSBmcmVhZCgnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2xnZWxsaXMvU1RFTS9tYXN0ZXIvREFUQS1BUlQtMS9EYXRhL0ZpbmFsRGF0YU5vcm1hbGl6ZWRDYXJlZXIuY3N2JykKaGVhZChkZk5vcm1hbCkKYGBgCgojIERhdGEgdmlzdWFsaXphdGlvbgoKIyMjIENvcnJlbGF0aW9uIGNoYXJ0cwoKU2VlIGhvdyB0aGUgdmFyaWFibGVzIGNvbGxlY3RlZCByZWxhdGUgdG8gb25lIGFub3RoZXIKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjICAgQ09SUkVMQVRJT04gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgoKIyBDcmVhdGUgdGhlIENvcnJlbGF0aW9uIFBsb3RzCgpjb3JEZiA8LSBkZlsgLCA4OjExXQpjb3JEZiA8LXNhcHBseShjb3JEZiwgRlVOID0gYXMubnVtZXJpYykgCmNvckRmIDwtY29yRGZbY29tcGxldGUuY2FzZXMoY29yRGYpLCBdCgojTWFrZSB0aGUgY29ycmVsYXRpb24gbWF0cml4CmNvck1hdHJpeCA8LWNvcihjb3JEZiwgdXNlPSJjb21wbGV0ZS5vYnMiLCBtZXRob2Q9InBlYXJzb24iKQpjb3JNYXRyaXgKCiNQbG90IG51bWVyb3VzIGZvcm1hdHMgb2YgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeApjb3JycGxvdChjb3JNYXRyaXgsIHR5cGUgPSAidXBwZXIiLCBvcmRlciA9ICJoY2x1c3QiLCBjb2wgPSBjKCJibGFjayIsICJ3aGl0ZSIpLCBiZyA9ICJsaWdodGJsdWUiLCB0bC5jb2wgPSAiYmxhY2siKQpjb3JycGxvdChjb3JNYXRyaXgsIG1ldGhvZD0iY2lyY2xlIiwgdGwuY29sID0gImJsYWNrIikKY29ycnBsb3QoY29yTWF0cml4LCBtZXRob2Q9InNxdWFyZSIsIHRsLmNvbCA9ICJibGFjayIpCmNvcnJwbG90KGNvck1hdHJpeCwgbWV0aG9kPSJudW1iZXIiLCB0bC5jb2wgPSAiYmxhY2siKQpjb3JycGxvdChjb3JNYXRyaXgsIG1ldGhvZD0ic2hhZGUiLCB0bC5jb2wgPSAiYmxhY2siKQpjb3JycGxvdC5taXhlZChjb3JNYXRyaXgsIHRsLmNvbCA9ICJibGFjayIpCgoKYGBgCgojIyMgU2NhdHRlcnBsb3RzIGFuZCBHZW5kZXIKCmBgYHtyfQojR2VuZGVyIEJhc2VkIEdyYXBocwojIHBsZWFzZSBpZ25vcmUgYWxsIG9mIHRoZSBsYXp5IG5hbWluZyA6KSAKCiNTY3JlZW4sIFNsZWVwIGFuZCBHZW5kZXIKc2NhdDIgPC1nZ3Bsb3QoZGYsIGFlcyh4PVNsZWVwLCB5PVNjcmVlblRpbWUsIGNvbG91cj1HZW5kZXIpKQpzY2F0MiA8LSBzY2F0MiArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IG1mUGFsZXR0ZSkgKyBnZW9tX2NvdW50KCkgCnNjYXQyICsgIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKyAgCiAgZmFjZXRfd3JhcCggfiBHZW5kZXIsIG5jb2w9MikgKwogIGxhYnModGl0bGUgPSAiVGltZSBTcGVudCBvbiBTY3JlZW4gdnMgU2xlZXAgQ29uc2lkZXJpbmcgR2VuZGVyIiwKICAgICAgIHggPSAiSG91cnMgb2YgU2xlZXAgcGVyIE5pZ2h0IiwgeSA9ICJIb3VycyBvZiBTY3JlZW4gVGltZSBQZXIgRGF5IikKCgoKI1NjcmVlbiwgU2xlZXAsIFBoeXNpY2FsIEFjdGl2aXR5IGFuZCBHZW5kZXIKCnNjYXQyIDwtZ2dwbG90KGRmLCBhZXMoeD1TbGVlcCwgeT1TY3JlZW5UaW1lLCBjb2xvdXI9R2VuZGVyLCBzaXplPVBoeXNBY3RpdmUpKQpzY2F0MiA8LSBzY2F0MiArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IG1mUGFsZXR0ZSkgKyBnZW9tX3BvaW50KCkgCnNjYXQyICsgIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKwogIGZhY2V0X3dyYXAoIH4gR2VuZGVyLCBuY29sPTIpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gU2NyZWVuIHZzIFNsZWVwIENvbnNpZGVyaW5nIEdlbmRlciBhbmQgUGh5c2ljYWwgQWN0aXZpdHkiLAogICAgICAgeCA9ICJIb3VycyBvZiBTbGVlcCBwZXIgTmlnaHQiLCB5ID0gIkhvdXJzIG9mIFNjcmVlbiBUaW1lIFBlciBEYXkiKQoKCiNIb21ld29yaywgU2xlZXAsIFBoeXNpY2FsIEFjdGl2aXR5IGFuZCBHZW5kZXIKc2NhdDIgPC1nZ3Bsb3QoZGYsIGFlcyh4PVNsZWVwLCB5PUhyc0hvbWV3b3JrLCBjb2xvdXI9R2VuZGVyLCBzaXplPVBoeXNBY3RpdmUpKQpzY2F0MiA8LSBzY2F0MiArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9IG1mUGFsZXR0ZSkgKyBnZW9tX3BvaW50KCkgCnNjYXQyICsgIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKwogIGZhY2V0X3dyYXAoIH4gR2VuZGVyLCBuY29sPTIpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gSG9td29yayB2cyBTbGVlcCBDb25zaWRlcmluZyBHZW5kZXIgYW5kIFBoeXNpY2FsIEFjdGl2aXR5IiwKICAgICAgIHggPSAiSG91cnMgb2YgU2xlZXAgcGVyIE5pZ2h0IiwgeSA9ICJIb3VycyBvZiBIb21ld29yayBUaW1lIFBlciBXZWVrIikKCgpgYGAKCgojIyBTY2F0dGVycGxvdHMgZXhwbG9yaW5nIHNsZWVwIHRpbWUgYW5kIHNjcmVlbiB0aW1lCgpgYGB7cn0KIyBOdW1lcmljYWwgUmVsYXRpb25zCgojU2xlZXAgYW5kIFNjcmVlbnRpbWUgCnNjYXQyIDwtZ2dwbG90KGRmLCBhZXMoeD1TbGVlcCwgeT1TY3JlZW5UaW1lLCBzaXplPTEvNSwgYWxwaGE9MC4wNSkpCnNjYXQyIDwtIHNjYXQyICArIGdlb21fcG9pbnQoKSAKc2NhdDIgKyAgc3RhdF9zbW9vdGgobWV0aG9kPWxtLCBmaWxsPSIjQkFENkVCIiwgY29sb3VyPSIjMDgzMDZCIiwgc2l6ZT0yKSArCiAgdGhlbWVfYncoKSArIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJUaW1lIFNwZW50IG9uIFNsZWVwIHZzIFNjcmVlbiBUaW1lIiwKICAgICAgIHggPSAiSG91cnMgb2YgU2xlZXAgcGVyIE5pZ2h0IiwgeSA9ICJIb3VycyBvZiBTY3JlZW4gVGltZSBQZXIgRGF5IikgCgoKCiNTbGVlcCBhbmQgR3JhZGUgCnNjYXQyIDwtZ2dwbG90KGRmLCBhZXMoeD1TbGVlcCwgeT1HcmFkZSwgc2l6ZT0xLzUsIGFscGhhPTAuMDUpKQpzY2F0MiA8LSBzY2F0MiAgKyBnZW9tX3BvaW50KCkgCnNjYXQyICsgIHN0YXRfc21vb3RoKG1ldGhvZD1sbSwgZmlsbD0iI0JBRDZFQiIsIGNvbG91cj0iIzA4MzA2QiIsIHNpemU9MikgKwogIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiVGltZSBTcGVudCBvbiBTbGVlcCB2cyBHcmFkZSIsCiAgICAgICB4ID0gIkhvdXJzIG9mIFNsZWVwIHBlciBOaWdodCIsIHkgPSAiR3JhZGUiKSAKCgoKI1NjcmVlblRpbWUgYW5kIEdyYWRlIApzY2F0MiA8LWdncGxvdChkZiwgYWVzKHg9U2NyZWVuVGltZSwgeT1HcmFkZSwgc2l6ZT0xLzUsIGFscGhhPTAuMDUpKQpzY2F0MiA8LSBzY2F0MiAgKyBnZW9tX3BvaW50KCkgCnNjYXQyICsgIHN0YXRfc21vb3RoKG1ldGhvZD1sbSwgZmlsbD0iI0JBRDZFQiIsIGNvbG91cj0iIzA4MzA2QiIsIHNpemU9MikgKwogIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiU2NyZWVuIFRpbWUgdnMgR3JhZGUiLAogICAgICAgeCA9ICJIb3VycyBvZiBTY3JlZW4gVGltZSIsIHkgPSAiR3JhZGUiKSAKCgojU2xlZXAgYW5kIFNjcmVlbnRpbWUgLSBGYWNldCBXcmFwIGJ5IEdyYWRlIHRvIHNlZSBpZiBpdCdzIGEgY29tbW9uIHRyZW5kIHdpdGhvdXQgYWdlIAojIGFzIGNvbmZvdW5kaW5nIGZhY3RvcgoKc2NhdDIgPC1nZ3Bsb3QoZGYsIGFlcyh4PVNsZWVwLCB5PVNjcmVlblRpbWUsIGFscGhhPTAuMDUpKQpzY2F0MiA8LSBzY2F0MiArIGdlb21fcG9pbnQoKQpzY2F0MiArICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICsKICBzdGF0X3Ntb290aChtZXRob2Q9bG0sIGZpbGw9IiNCQUQ2RUIiLCBjb2xvdXI9IiMwODMwNkIiLCBzaXplPTEpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gU2NyZWVuIHZzIFNsZWVwIGJ5IEdyYWRlIiwKICAgICAgIHggPSAiSG91cnMgb2YgU2xlZXAgcGVyIE5pZ2h0IiwgeSA9ICJIb3VycyBvZiBTY3JlZW4gVGltZSBQZXIgRGF5IikgKwogIGZhY2V0X3dyYXAoIH4gR3JhZGUsIG5jb2w9MikKCgpgYGAKCgojIyBNb3JlIE51bWVyaWNhbCBSZWxhdGlvbnMKYGBge3J9CiNDaGFydCA2Cgp2aW9saW4gPC1nZ3Bsb3QoZGYsIGFlcyh5PVNsZWVwLCB4PUludEV4dCkpIAp2aW9saW4gKyBnZW9tX3Zpb2xpbih0cmltPUZBTFNFLCBmaWxsPSJsaWdodGJsdWUiKSAgKyAgCiAgdGhlbWVfYncoKSArIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJUaW1lIFNwZW50IG9uIFNsZWVwIGJ5IFNvY2lhbCBGYWN0b3JzIiwKICAgICAgIHggPSAiSG91cnMgb2YgU2xlZXAgcGVyIE5pZ2h0IikKCgoKI1NsZWVwLCBIb21ld29yayBhbmQgU3ViamVjdApzY2F0MyA8LWdncGxvdChkZiwgYWVzKHg9SHJzSG9tZXdvcmssIHk9U2xlZXAsIGNvbG91cj1TdWJqZWN0KSkKc2NhdDM8LSBzY2F0MyArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkKc2NhdDMgKyBmYWNldF93cmFwKCB+IFN1YmplY3QsIG5jb2w9MikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBibHVlUGFsZXR0ZSkgICsKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gSG9td29yayB2cyBTbGVlcCBDb25zaWRlcmluZyBTdHVkZW50cyBGYXZvcml0ZSBTdWJqZWN0IiwKICAgICAgIHggPSAiSG91cnMgb2YgU2xlZXAgcGVyIE5pZ2h0IiwgeSA9ICJIb3VycyBvZiBIb21ld29yayBQZXIgV2VlayIpCgoKCiMgQWdlIGRpZmZlcmVuY2VzCgojIFNsZWVwIGJ5IEFnZQoKc2xlZXBUaW1lIDwtZ2dwbG90KGRmLCBhZXMoeT1TbGVlcCwgeD1HcmFkZSkpIApzbGVlcFRpbWUgKyBnZW9tX2NvdW50KHRyaW09RkFMU0UsIGZpbGw9ImxpZ2h0Ymx1ZSIpICArICAKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICsKICBzdGF0X3Ntb290aChtZXRob2Q9bG0sIGZpbGw9IiNCQUQ2RUIiLCBjb2xvdXI9IiMwODMwNkIiLCBzaXplPTIpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gU2xlZXAgYnkgR3JhZGUiLAogICAgICAgeSA9ICJIb3VycyBvZiBTbGVlcCBwZXIgTmlnaHQiLCB4PSJHcmFkZSIpCgojIEhvbWV3b3JrIGJ5IEFnZQoKaG9tZXdvcmtUaW1lIDwtZ2dwbG90KGRmLCBhZXMoeT1IcnNIb21ld29yaywgeD1HcmFkZSkpIApob21ld29ya1RpbWUgKyBnZW9tX2NvdW50KHRyaW09RkFMU0UsIGZpbGw9ImxpZ2h0Ymx1ZSIpICArICAKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICsKICBzdGF0X3Ntb290aChtZXRob2Q9bG0sIGZpbGw9IiNCQUQ2RUIiLCBjb2xvdXI9IiMwODMwNkIiLCBzaXplPTIpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gSG9tZXdvcmsgYnkgR3JhZGUiLAogICAgICAgeSA9ICJIb3VycyBvZiBIb21ld29yayBwZXIgV2VlayIsIHg9IkdyYWRlIikKCgojIFBoeXNpY2FsIEFjdGl2aXR5IGJ5IEFnZQoKcGh5c1RpbWUgPC1nZ3Bsb3QoZGYsIGFlcyh5PVBoeXNBY3RpdmUsIHg9R3JhZGUpKSAKcGh5c1RpbWUgKyBnZW9tX2NvdW50KHRyaW09RkFMU0UsIGZpbGw9ImxpZ2h0Ymx1ZSIpICArICAKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICsKICBzdGF0X3Ntb290aChtZXRob2Q9bG0sIGZpbGw9IiNCQUQ2RUIiLCBjb2xvdXI9IiMwODMwNkIiLCBzaXplPTIpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gUGh5c2ljYWwgQWN0aXZpdHkgYnkgR3JhZGUiLAogICAgICAgeSA9ICJIb3VycyBvZiBQaHlzaWNhbCBBY3Rpdml0eSBwZXIgV2VlayIsIHg9IkdyYWRlIikKCiMgU2NyZWVuIFRpbWUgYnkgQWdlCgpzY3JlZW5UaW1lIDwtZ2dwbG90KGRmLCBhZXMoeT1TY3JlZW5UaW1lLCB4PUdyYWRlKSkgCnNjcmVlblRpbWUgKyBnZW9tX2NvdW50KHRyaW09RkFMU0UsIGZpbGw9ImxpZ2h0Ymx1ZSIpICArICAKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICsKICBzdGF0X3Ntb290aChtZXRob2Q9bG0sIGZpbGw9IiNCQUQ2RUIiLCBjb2xvdXI9IiMwODMwNkIiLCBzaXplPTIpICsKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gU2NyZWVucyBieSBHcmFkZSIsCiAgICAgICB5ID0gIkhvdXJzIG9mIFNjcmVlbiBUaW1lIHBlciBEYXkiLCB4PSJHcmFkZSIpCgoKI1N1bW1hcnkgb2YgZ3JhZGUgLSBhdmVyYWdlIHNjcmVlbnRpbWUsIHNsZWVwLCBwaHlzaWNhbCBhY3Rpdml0eSBldGMKCgpncmFkZVN1bW1hcnkgPC0gZGYgJT4lCiAgZ3JvdXBfYnkoR3JhZGUpICU+JQogIHN1bW1hcml6ZShTY3JlZW5UaW1lRGF5ID0gbWVhbihTY3JlZW5UaW1lLCBuYS5ybSA9IFRSVUUpLCBTbGVlcERheSA9IG1lYW4oU2xlZXAsIG5hLnJtID0gVFJVRSksIAogICAgICAgICAgICBQaHlzQWN0aXZlRGF5ID0gbWVhbihQaHlzQWN0aXZlLCBuYS5ybSA9IFRSVUUpLCBIb21ld29ya0RheSA9IG1lYW4oSHJzSG9tZXdvcmssIG5hLnJtID0gVFJVRSkpICAlPiUKICBnYXRoZXIobWVhc3VyZW1lbnQsIGF2ZXJhZ2UsIFNjcmVlblRpbWVEYXk6SG9tZXdvcmtEYXkpCgoKYGBgCgoKIyMjIENvbWJpbmF0aW9uIG9mIHBsb3RzIHVzaW5nIGdnc3RhdHNwbG90CgpgYGB7cn0KIyBnZ3N0YXRzcGxvdAoKCgpnZ3N0YXRzcGxvdDo6Z2dzY2F0dGVyc3RhdHMoCiAgZGF0YSA9IGRmLCAKICB4ID0gU2NyZWVuVGltZSwgCiAgeSA9IFNsZWVwLAogIHRpdGxlID0gIkhvdXJzIFNsZWVwIHZzIFNjcmVlbiBUaW1lIiwKICBtZXNzYWdlcyA9IEZBTFNFLCAKICBtYXJnaW5hbC50eXBlID0gImhpc3RvZ3JhbSIsIAogIGxpbmUuY29sb3IgPSAiIzA4MzA2QiIsIAogIHhmaWxsID0gIiNCQUQ2RUIiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIHlmaWxsID0gIiM1MzlFQ0MiLCAgCikKCiMgcGxvdApnZ3N0YXRzcGxvdDo6Z2diZXR3ZWVuc3RhdHMoCiAgZGF0YSA9IGRmLCAKICB4ID0gR2VuZGVyLCAKICB5ID0gSHJzSG9tZXdvcmssCiAgbWVzc2FnZXMgPSBGQUxTRQopCgojSGlzdG9ncmFtCmdnc3RhdHNwbG90OjpnZ2hpc3Rvc3RhdHMoCiAgZGF0YSA9IGRmLAogIHggPSBQaHlzQWN0aXZlLAogIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBQaHlzaWNhbGx5IEFjdGl2ZSBIb3VycyIsCiAgdHlwZSA9ICJwYXJhbWV0cmljIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG9uZSBzYW1wbGUgdC10ZXN0CiAgdGVzdC52YWx1ZSA9IDMsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGRlZmF1bHQgdmFsdWUgaXMgMAogIGNlbnRyYWxpdHkucGFyYSA9ICJtZWFuIiwgICAgICAgICAgICAgICAgICAgICAgIyB3aGljaCBtZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGVuY3kgaXMgdG8gYmUgcGxvdHRlZAogIGNlbnRyYWxpdHkuY29sb3IgPSAiZGFya3JlZCIsICAgICAgICAgICAgICAgICAgIyBkZWNpZGVzIGNvbG9yIG9mIHZlcnRpY2FsIGxpbmUgcmVwcmVzZW50aW5nIGNlbnRyYWwgdGVuZGVuY3kKICBiaW53aWR0aCA9IDAuMTAsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYmlud2lkdGggdmFsdWUgKGV4cGVyaW1lbnQgdW50aWwgeW91IGZpbmQgdGhlIGJlc3Qgb25lKQogIG1lc3NhZ2VzID0gRkFMU0UgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0dXJuIG9mZiB0aGUgbWVzc2FnZXMKKSAKCgpgYGAKCgoKIyMjIFdvcmQgQ2xvdWRzCgojIyMjIENhcmVlcgoKYGBge3J9CgojRGF0YSBzZXQgaXMgZGZOb3JtYWwKaGVhZChkZk5vcm1hbCkKCgojIyBDYXJlZXIgaXMgZmlyc3QKCiNQcm9jZXNzIERhdGEKCiNVbm5lc3QgdGhlIHdvcmRzIC0gY29kZSB2aWEgVGlkeSBUZXh0Cgp0YWJsZTIgPC0gZGZOb3JtYWwgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgQ2FyZWVyKQoKI3JlbW92ZSBzdG9wIHdvcmRzIC0gYWthIHR5cGljYWxseSB2ZXJ5IGNvbW1vbiB3b3JkcyBzdWNoIGFzICJ0aGUiLCAib2YiIGV0YwpoZWFkKHRhYmxlMikKZGF0YShzdG9wX3dvcmRzKQoKY2FyZWVyIDwtIHRhYmxlMiAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcykgJT4lCiAgZmlsdGVyKCEgd29yZD09J3BsYXllcicpCgoKI0dpcmwgVmlldwoKY2FyZWVyR2lybCA8LSB0YWJsZTIgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JQogIGZpbHRlcighIHdvcmQ9PSdwbGF5ZXInKSAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQoKCmNhcmVlckJveSA8LSB0YWJsZTIgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JQogIGZpbHRlcighIHdvcmQ9PSdwbGF5ZXInKSAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikKCiNkbyBhIHdvcmQgY291bnQKY2FyZWVyQm95IDwtIGNhcmVlckJveSAlPiUKICBkcGx5cjo6Y291bnQod29yZCwgc29ydCA9IFRSVUUpIApjYXJlZXJCb3kKCgpjYXJlZXJHaXJsIDwtIGNhcmVlckdpcmwgJT4lCiAgZHBseXI6OmNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAKY2FyZWVyR2lybAoKCiNNYWtlIHdvcmRjbG91ZAp3b3JkY2xvdWQyKGNhcmVlckdpcmwpCndvcmRjbG91ZDIoY2FyZWVyQm95LCBzaXplPTEsICBjb2xvcj1ib3lDb2wpCgoKI0NhcmVlciBCYXIgQ2hhcnRzCmNhcmVlckdpcmwkZ2VuZGVyIDwtICdmZW1hbGUnCmNhcmVlckJveSRnZW5kZXIgPC0gJ21hbGUnCmNhcmVlckZ1bGwgPC1yYmluZChjYXJlZXJCb3ksIGNhcmVlckdpcmwpCmNhcmVlckZ1bGwKCmNhcmVlckZ1bGwgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4sIGZpbGwgPSBnZW5kZXIpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofmdlbmRlciwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YyhnaXJsQ29sLCBib3lDb2wpKSArIAogIGxhYnMoeSA9ICJNYWxlIHZzIEZlbWFsZSBDYXJlZXJzIiwKICAgICAgIHggPSBOVUxMKSArCiAgY29vcmRfZmxpcCgpICArCiAgdGhlbWVfYncoKSArIHRoZW1lX21pbmltYWwoKSAKCmBgYAoKCmBgYHtyfQoKY2FyZWVyR2lybCAlPiUKICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgbikpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lCiAgc2xpY2UoMToxMCkgJT4lCiAgZ2dwbG90KGFlcyh3b3JkLCBuKSkgKwogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UsIGZpbGw9Z2lybENvbCkgKwogIGxhYnModGl0bGUgPSAiVG9wIDEwIEdpcmwgQ2FyZWVycyIsCiAgICAgICB5PU5VTEwsIAogICAgICAgeCA9IE5VTEwpICsKICBjb29yZF9mbGlwKCkgICsKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICArIAogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwLCBmYWNlPSJib2xkIiksIAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTMwLCBmYWNlPSJib2xkIiwgaGp1c3QgPSAwLjUpKQoKCgpgYGAKCmBgYHtyfQpib3lDb2wgPC0gIiM1ODhDQTgiCgpjYXJlZXJCb3kgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBhcnJhbmdlKGRlc2MobikpICU+JQogIHNsaWNlKDE6MTApICU+JQogIGdncGxvdChhZXMod29yZCwgbikpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFLCBmaWxsPWJveUNvbCkgKwogIGxhYnModGl0bGUgPSAiVG9wIDEwIEJveSBDYXJlZXJzIiwKICAgICAgIHk9TlVMTCwgCiAgICAgICB4ID0gTlVMTCkgKwogIGNvb3JkX2ZsaXAoKSAgKwogIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgICsgCiAgdGhlbWUoCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhY2U9ImJvbGQiKSwgCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MzAsIGZhY2U9ImJvbGQiLCBoanVzdCA9IDAuNSkpCmBgYAoKCgojIyMjIEhvYmJpZXMgd29yZCBjbG91ZHMKYGBge3J9CgojIyMgSG9iYmllcyAjIyMKCmhlYWQoZGZOb3JtYWwpCiNVbm5lc3QgdGhlIHdvcmRzIC0gY29kZSB2aWEgVGlkeSBUZXh0CgojQ29tYmluZSB0aGUgaG9iYmllcyBjb2x1bW4KZGZOb3JtYWwkaGIgPC0gcGFzdGUoZGZOb3JtYWwkU3BlbmRUaW1lMSwgZGZOb3JtYWwkU3BlbmRUaW1lMiwgc2VwPSAiICIpCmRmTm9ybWFsJGhiCgojVW5uZXN0IHRoZSB3b3JkcyAtIGNvZGUgdmlhIFRpZHkgVGV4dAoKdGFibGUyIDwtIGRmTm9ybWFsICU+JSAKICB1bm5lc3RfdG9rZW5zKHdvcmQsIGhiKQoKI3JlbW92ZSBzdG9wIHdvcmRzIC0gYWthIHR5cGljYWxseSB2ZXJ5IGNvbW1vbiB3b3JkcyBzdWNoIGFzICJ0aGUiLCAib2YiIGV0YwoKaGVhZCh0YWJsZTIpCmRhdGEoc3RvcF93b3JkcykKCmhvYmJpZXMgPC0gdGFibGUyICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBmaWx0ZXIoISB3b3JkPT0ncGxheWVyJykKCmhvYmJpZXNHaXJsIDwtIHRhYmxlMiAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcykgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIikKCmhvYmJpZXNCb3kgPC0gdGFibGUyICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikKCiNkbyBhIHdvcmQgY291bnQKCmhvYmJpZXMgPC0gaG9iYmllcyAlPiUKICBkcGx5cjo6Y291bnQod29yZCwgc29ydCA9IFRSVUUpIApob2JiaWVzIAoKaG9iYmllc0dpcmwgPC0gaG9iYmllc0dpcmwgJT4lCiAgZHBseXI6OmNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAKaG9iYmllc0dpcmwKCmhvYmJpZXNCb3kgPC0gaG9iYmllc0JveSAlPiUKICBkcGx5cjo6Y291bnQod29yZCwgc29ydCA9IFRSVUUpIApob2JiaWVzQm95CgoKI2Rvd25sb2FkIHN5bWJvbAoKdXJsIDwtICJodHRwczovL2dpdGh1Yi5jb20vbGdlbGxpcy9TVEVNL2Jsb2IvbWFzdGVyL0RBVEEtQVJULTEvU3ltYm9scy9zb2NjZXIxLnBuZz9yYXc9dHJ1ZSIKaW1nIDwtICJzb2NjZXIxLnBuZyIKZG93bmxvYWQuZmlsZSh1cmwsIGltZykgIyBkb3dubG9hZCBmaWxlCgp1cmwgPC0gImh0dHBzOi8vZ2l0aHViLmNvbS9sZ2VsbGlzL1NURU0vYmxvYi9tYXN0ZXIvREFUQS1BUlQtMS9TeW1ib2xzL2dpcmwzLnBuZz9yYXc9dHJ1ZSIKaW1nR2lybCA8LSAiZ2lybDMucG5nIgpkb3dubG9hZC5maWxlKHVybCwgaW1nR2lybCkgIyBkb3dubG9hZCBmaWxlCgp1cmwgPC0gImh0dHBzOi8vZ2l0aHViLmNvbS9sZ2VsbGlzL1NURU0vYmxvYi9tYXN0ZXIvREFUQS1BUlQtMS9TeW1ib2xzL2tpZC5wbmc/cmF3PXRydWUiCmltZ0JveSA8LSAia2lkLnBuZyIKZG93bmxvYWQuZmlsZSh1cmwsIGltZ0JveSkgIyBkb3dubG9hZCBmaWxlCgojTWFrZSB3b3JkY2xvdWQKd29yZGNsb3VkMihob2JiaWVzKQp3b3JkY2xvdWQyKGhvYmJpZXNCb3kpCgp3b3JkY2xvdWQyKGhvYmJpZXMsIHNpemU9MywgZmlnUGF0aCA9IGltZykKCiMjIGdpcmwgaG9iYmllcyBib3kgaG9iYmllcwoKd29yZGNsb3VkMihob2JiaWVzR2lybCwgc2l6ZT0xLCBmaWdQYXRoID0gaW1nR2lybCwgY29sb3I9Z2lybENvbCApCndvcmRjbG91ZDIoaG9iYmllc0JveSwgc2l6ZT0zLCBmaWdQYXRoID0gaW1nQm95LCBjb2xvcj1ib3lDb2wpIAoKIyBIb2JiaWVzIGJhciBjaGFydHMKaG9iYmllc0dpcmwkZ2VuZGVyIDwtICdmZW1hbGUnCmhvYmJpZXNCb3kkZ2VuZGVyIDwtICdtYWxlJwpmdWxsSG9iYmllcyA8LXJiaW5kKGhvYmJpZXNCb3ksIGhvYmJpZXNHaXJsKQpmdWxsSG9iYmllcwoKI1JhbmtlZCBsaXN0IG9mIGhvYmJpZXMKZnVsbEhvYmJpZXMgJT4lCiAgZ3JvdXBfYnkod29yZCkgJT4lIAogIHN1bW1hcml6ZShuPXN1bShuKSkgJT4lIAogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUKICBzbGljZSgxOjEwKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4pKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSwgZmlsbD1ib3lDb2wpICsKICBsYWJzKHRpdGxlID0gIlRvcCAxMCBIb2JiaWVzIiwKICAgICAgIHk9TlVMTCwgCiAgICAgICB4ID0gTlVMTCkgKwogIGNvb3JkX2ZsaXAoKSAgKwogIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgICsgCiAgdGhlbWUoCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTQsIGZhY2U9ImJvbGQiKSwgCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjAsIGZhY2U9ImJvbGQiLCBoanVzdCA9IDAuNSkpCgoKYGBgCgoKIyMjIyBTZWxmIHBlcmNlcHRpb24gCgpgYGB7cn0KI0NvbWJpbmUgdGhlIGhvYmJpZXMgY29sdW1uCmRmTm9ybWFsJHNlbGYgPC0gcGFzdGUoZGZOb3JtYWwkU2VsZjEsIGRmTm9ybWFsJFNlbGYyLCBzZXA9ICIgIikKZGZOb3JtYWwkc2VsZgoKI1VubmVzdCB0aGUgd29yZHMgLSBjb2RlIHZpYSBUaWR5IFRleHQKCnRhYmxlMiA8LSBkZk5vcm1hbCAlPiUgCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCBzZWxmKQoKCiNyZW1vdmUgc3RvcCB3b3JkcyAtIGFrYSB0eXBpY2FsbHkgdmVyeSBjb21tb24gd29yZHMgc3VjaCBhcyAidGhlIiwgIm9mIiBldGMKCnNlbGYgPC0gdGFibGUyICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAKc2VsZgoKc2VsZkdpcmwgPC0gdGFibGUyICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQoKc2VsZkJveSA8LSB0YWJsZTIgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIm1hbGUiKQoKI2RvIGEgd29yZCBjb3VudAoKc2VsZiA8LSBzZWxmICU+JQogIGRwbHlyOjpjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgCnNlbGYgCgpzZWxmR2lybCA8LSBzZWxmR2lybCAlPiUKICBkcGx5cjo6Y291bnQod29yZCwgc29ydCA9IFRSVUUpIApzZWxmR2lybAoKc2VsZkJveSA8LSBzZWxmQm95ICU+JQogIGRwbHlyOjpjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgCnNlbGZCb3kKCgojZG93bmxvYWQgc3ltYm9sCgp1cmwgPC0gImh0dHBzOi8vZ2l0aHViLmNvbS9sZ2VsbGlzL1NURU0vYmxvYi9tYXN0ZXIvREFUQS1BUlQtMS9TeW1ib2xzL2hlYXJ0LnBuZz9yYXc9dHJ1ZSIKaGVhcnRpbWcgPC0gImhlYXJ0LnBuZyIKZG93bmxvYWQuZmlsZSh1cmwsIGhlYXJ0aW1nKSAjIGRvd25sb2FkIGZpbGUKCiNNYWtlIHdvcmRjbG91ZAp3b3JkY2xvdWQyKHNlbGYsIHNpemU9MSkKd29yZGNsb3VkMihzZWxmLCBzaXplPTMsIGZpZ1BhdGggPSBoZWFydGltZyApCgp3b3JkY2xvdWQyKHNlbGZCb3ksIHNpemU9MS41LCBmaWdQYXRoID0gaGVhcnRpbWcsIGNvbG9yPWJveUNvbCApCndvcmRjbG91ZDIoc2VsZkdpcmwsIHNpemU9MS41LCBmaWdQYXRoID0gaGVhcnRpbWcsIGNvbG9yPWdpcmxDb2wgKQoKIyBTZWxmIGJhciBjaGFydHMKc2VsZkdpcmwkZ2VuZGVyIDwtICdmZW1hbGUnCnNlbGZCb3kkZ2VuZGVyIDwtICdtYWxlJwpmdWxsU2VsZiA8LXJiaW5kKHNlbGZCb3ksIHNlbGZHaXJsKQpmdWxsU2VsZgoKZnVsbFNlbGYgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4sIGZpbGwgPSBnZW5kZXIpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGZhY2V0X3dyYXAofmdlbmRlciwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YyhnaXJsQ29sLCBib3lDb2wpKSArCiAgbGFicyh5ID0gIk1hbGUgdnMgRmVtYWxlIFNlbGYgRGVzY3JpcHRpb24iLAogICAgICAgeCA9IE5VTEwpICsKICBjb29yZF9mbGlwKCkgICsKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpIAoKCgoKYGBgCgojIyMgU2VsZiBwZXJjZXB0aW9uIHNlbnRpbWVudCBhbmFseXNpcwoKYGBge3J9CiMgU2VudGltZW50IEFuYWx5c2lzIC0gZG8gb24gdGhlIGZ1bGwgZGF0YQoKP2dldF9zZW50aW1lbnRzCiNhZmlubiBpcyBudW1lcmljIHNjYWxlLCBiaW5nIGlzICt2ZS8tdmUsIAojbnJjIGlzIG1vcmUgZGV0YWlsZWQgKGllIHRydXN0LCBmZWFyIGV0YyksIGxvdWdocmFuIGlzICt2ZS8tdmUKc2VudGltZW50cyA8LSBnZXRfc2VudGltZW50cygiYWZpbm4iKSAKc2VudGltZW50cwoKIyMgR2V0IHJhdyB3b3JkIGFuZCBnZW5kZXIgKDEgcm93IHBlciBpbnN0YW5jZSBvZiBhc3NpZ25tZW50KQoKaGVhZChkZk5vcm1hbCkKc2VsZjEgPC0gYXMuZGF0YS5mcmFtZShkZk5vcm1hbFssYygiR2VuZGVyIiwgIlNlbGYxIildKQpzZWxmMiA8LSBhcy5kYXRhLmZyYW1lKGRmTm9ybWFsWyxjKCJHZW5kZXIiLCAiU2VsZjIiKV0pCgpoZWFkKHNlbGYyKQojVE8gRE8gcmVuYW1lIHNlbGYxIGFuZCBzZWxmMiAKCm5hbWVzKHNlbGYxKVsyXTwtIndvcmQiCm5hbWVzKHNlbGYyKVsyXTwtIndvcmQiCmZ1bGxTdGFja1NlbGYgPC1yYmluZChzZWxmMSwgc2VsZjIpCmhlYWQoZnVsbFN0YWNrU2VsZikKCiNhZGQgc2VudGltZW50CgpzZW50aW1lbnRzIDwtIGdldF9zZW50aW1lbnRzKCJhZmlubiIpIAoKZnVsbFN0YWNrU2VsZlNlbnRpbWVudCA8LSBmdWxsU3RhY2tTZWxmICU+JQogIGlubmVyX2pvaW4oc2VudGltZW50cykKZnVsbFN0YWNrU2VsZlNlbnRpbWVudAoKI0F2ZXJhZ2VzCnN1bW1hcnlHZW5kZXJTZW50aW1lbnQgPC0gZnVsbFN0YWNrU2VsZlNlbnRpbWVudCAlPiUgCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBkcGx5cjo6c3VtbWFyaXplKGF2Z1NlbnRpbWVudFNjb3JlID0gbWVhbihzY29yZSwgbmEucm0gPSBUUlVFKSwgCiAgICAgICAgICAgIG1lZFNlbnRpbWVudFNjb3JlID0gbWVkaWFuKHNjb3JlLCBuYS5ybSA9IFRSVUUpLCAKICAgICAgICAgICAgY291bnRXb3JkcyA9IGxlbmd0aCh3b3JkKSkKCm5hbWVzKHN1bW1hcnlHZW5kZXJTZW50aW1lbnQpIDwtIGMoIkdlbmRlciIsICJBdmcgU2VudGltZW50IFNjb3JlIiwgIk1lZGlhbiBTZW50aW1lbnQgU2NvcmUiLCAiV29yZCBDb3VudCIpCgoKZm9ybWF0dGFibGUoc3VtbWFyeUdlbmRlclNlbnRpbWVudCwgCiAgICAgICAgICAgIGxpc3QoIkF2ZyBTZW50aW1lbnQgU2NvcmUiID0gY29sb3JfdGlsZSgidHJhbnNwYXJlbnQiLCAiIzAwQTg2QiIpKSkKCmFzLmRhdGF0YWJsZShmb3JtYXR0YWJsZShzdW1tYXJ5R2VuZGVyU2VudGltZW50KSkKCiNib3ggcGxvdAoKZ2dwbG90KGZ1bGxTdGFja1NlbGZTZW50aW1lbnQsIGFlcyh4PUdlbmRlciwgeT1zY29yZSwgZmlsbD1HZW5kZXIpKSArIAogIGdlb21fYm94cGxvdChub3RjaD1UUlVFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoZ2VuZGVyTmV1dHJhbENvbCwgZ2lybENvbCwgYm95Q29sKSkgKwogIGxhYnModGl0bGUgPSAiU2VudGltZW50IFNjb3JlIGZvciBNYWxlIHZzIEZlbWFsZSBTZWxmIERlc2NyaXB0aW9uIiwKICAgICAgIHggPSBOVUxMKSArCiAgY29vcmRfZmxpcCgpICArCiAgdGhlbWVfYncoKSArIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKAogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE0ICksIAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE4LCBmYWNlPSJib2xkIiwgaGp1c3QgPSAwLjUpKQpgYGAKCgojIyMgQW5pbWF0aW9ucwoKTm90ZSB0aGF0IHRoZSBvdXRwdXQgd2lsbCBub3QgYmUgZGlzcGxheWVkIGluIAoKCmBgYHtyfQojI25vcm1hbApzY3JlZW5UaW1lIDwtZ2dwbG90KGRmLCBhZXMoeT1TY3JlZW5UaW1lLCB4PVBoeXNBY3RpdmUpKSAKc2NyZWVuVGltZSArIGdlb21fY291bnQodHJpbT1GQUxTRSwgZmlsbD0ibGlnaHRibHVlIikgICsgIAogIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKyAKICBsYWJzKHRpdGxlID0gIlRpbWUgU3BlbnQgb24gU2NyZWVucyBieSBHcmFkZSIsCiAgICAgICB5ID0gIkhvdXJzIG9mIFNjcmVlbiBUaW1lIHBlciBEYXkiLCB4PSJIb3VycyBQaHlzaWNhbGx5IEFjdGl2ZSBhIFdlZWsiKQoKI1RoZSBkb2NzIGNhbiBiZSBmb3VuZCBoZXJlOiBodHRwczovL2dpdGh1Yi5jb20vdGhvbWFzcDg1L2dnYW5pbWF0ZS9ibG9iL21hc3Rlci9SRUFETUUubWQKCgpsaWJyYXJ5KGdnYW5pbWF0ZSkKbGlicmFyeSh0d2VlbnIpCmxpYnJhcnkoZ2dhbmltYXRlKQoKIyNXaXRoIEFuaW1hdGlvbgoKc2NyZWVuVGltZSA8LWdncGxvdChkZiwgYWVzKHk9U2NyZWVuVGltZSwgeD1IcnNIb21ld29yaykpIApzY3JlZW5UaW1lICsgZ2VvbV9jb3VudCh0cmltPUZBTFNFLCBmaWxsPSJsaWdodGJsdWUiKSAgKyAgCiAgdGhlbWVfYncoKSArIHRoZW1lX21pbmltYWwoKSArIAogICMgSGVyZSBjb21lcyB0aGUgZ2dhbmltYXRlIHNwZWNpZmljIGJpdHMKICBsYWJzKHRpdGxlID0gJ0dyYWRlOiB7ZnJhbWVfdGltZX0nLCB4ID0gJ0hvdXJzIEhvbWV3b3JrIGEgV2VlaycsIHkgPSAnSG91cnMgb2YgU2NyZWVuIFRpbWUgcGVyIERheScpICsKICB0cmFuc2l0aW9uX3RpbWUoR3JhZGUpICsKICBlYXNlX2FlcygnbGluZWFyJykKCmBgYAoKCgoKCmBgYHtyfQoKIyMgU2Vjb25kIEFuaW1hdGlvbgoKZ2dwbG90KGRmLCBhZXMoeT1TY3JlZW5UaW1lLCB4PUhyc0hvbWV3b3JrLCBjb2xvciA9IEdlbmRlcikpICsKICBnZW9tX3BvaW50KCkgICsgIAogIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKyAKICAjIEhlcmUgY29tZXMgdGhlIGdnYW5pbWF0ZSBzcGVjaWZpYyBiaXRzCiAgbGFicyh0aXRsZSA9ICdHcmFkZToge2ZyYW1lX3RpbWV9JywgeCA9ICdIb3VycyBIb21ld29yayBhIFdlZWsnLCB5ID0gJ0hvdXJzIG9mIFNjcmVlbiBUaW1lIHBlciBEYXknKSArCiAgdHJhbnNpdGlvbl90aW1lKEdyYWRlKSArCiAgZWFzZV9hZXMoJ2xpbmVhcicpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1tZlBhbGV0dGUpCgpgYGAKCgoKYGBge3J9CgpnZ3Bsb3QoZGYsIGFlcyh5PVNjcmVlblRpbWUsIHg9SHJzSG9tZXdvcmssIGNvbG9yID0gR2VuZGVyKSkgKwogIGdlb21fcG9pbnQoKSAgKyAgCiAgdGhlbWVfYncoKSArIHRoZW1lX21pbmltYWwoKSArIAogICMgSGVyZSBjb21lcyB0aGUgZ2dhbmltYXRlIHNwZWNpZmljIGJpdHMKICBsYWJzKHRpdGxlID0gJ0dyYWRlOiB7ZnJhbWVfdGltZX0nLCB4ID0gJ0hvdXJzIEhvbWV3b3JrIGEgV2VlaycsIHkgPSAnSG91cnMgb2YgU2NyZWVuIFRpbWUgcGVyIERheScpICsKICB0cmFuc2l0aW9uX3RpbWUoR3JhZGUpICsKICBlYXNlX2Flcygnc2luZS1pbi1vdXQnKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9bWZQYWxldHRlKQoKYGBgCgoKYGBge3J9CiMjIFdpdGggYmV0dGVyIHRpdGxlcwoKZ2dwbG90KGRmLCBhZXMoeT1TY3JlZW5UaW1lLCB4PUhyc0hvbWV3b3JrLCBjb2xvciA9IEdlbmRlcikpICsKICBnZW9tX3BvaW50KHNpemUgPTcsIGFscGhhID0gMC40KSAgKyAgCiAgdGhlbWVfYncoKSArIHRoZW1lX21pbmltYWwoKSArIAogICMgSGVyZSBjb21lcyB0aGUgZ2dhbmltYXRlIHNwZWNpZmljIGJpdHMKICB0cmFuc2l0aW9uX3N0YXRlcygKICAgIEdyYWRlLAogICAgdHJhbnNpdGlvbl9sZW5ndGggPSA0LAogICAgc3RhdGVfbGVuZ3RoID0gMQogICkgKwogIGVudGVyX2ZhZGUoKSArIAogIGV4aXRfc2hyaW5rKCkgKwogIGVhc2VfYWVzKCdzaW5lLWluLW91dCcpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1tZlBhbGV0dGUpICsKICBsYWJzKHRpdGxlID0gJ0dyYWRlOiB7Y2xvc2VzdF9zdGF0ZX0nKQpgYGAKCgojU2xpZGluZyBoaXN0b2dyYW0KCiMjIFRlc3Qgb3V0IHRoZSBncmFwaApgYGB7cn0KZ2dwbG90KGRmLCBhZXMoeD0iIiwgeT1TY3JlZW5UaW1lKSkgKwogIGdlb21fYm94cGxvdChmaWxsID0gZ2VuZGVyTmV1dHJhbENvbCwgYWxwaGEgPSAwLjgsIGJpbndpZHRoPTMpICArICAKICB0aGVtZV9idygpICsgdGhlbWVfbWluaW1hbCgpICsgZmFjZXRfd3JhcCh+R3JhZGUpCmBgYAoKCiNNYWtlIHRoZSBhbmltYXRpb24KYGBge3J9CgoKZ2dwbG90KGRmLCBhZXMoeD0iIiwgeT1TY3JlZW5UaW1lKSkgKwogIGdlb21fYm94cGxvdChmaWxsID0gYm95Q29sLCBhbHBoYSA9IDAuOCkgICsgIAogIHRoZW1lX2J3KCkgKyB0aGVtZV9taW5pbWFsKCkgKwogICMgSGVyZSBjb21lcyB0aGUgZ2dhbmltYXRlIHNwZWNpZmljIGJpdHMKICB0cmFuc2l0aW9uX3N0YXRlcygKICAgIEdyYWRlLAogICAgdHJhbnNpdGlvbl9sZW5ndGggPSA0LAogICAgc3RhdGVfbGVuZ3RoID0gMQogICkgKwogIGVudGVyX2ZhZGUoKSArIAogIGV4aXRfc2hyaW5rKCkgKwogIGVhc2VfYWVzKCdzaW5lLWluLW91dCcpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1tZlBhbGV0dGUpICsKICBsYWJzKHRpdGxlID0gJ0dyYWRlOiB7Y2xvc2VzdF9zdGF0ZX0nLCAKICAgICAgICB4ID0iIiwgeSA9ICJTY3JlZW4gVGltZSIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0zMCwgZmFjZT0iYm9sZC5pdGFsaWMiLCBoanVzdCA9IDAuNSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCwgZmFjZT0iYm9sZCIpCikKYGBgCgoKCg==